// Profiler.cpp : Implementation of CProfiler

#include "stdafx.h"
#include "Profiler.h"
#include "NakedCallbacks.h"
#include "Logger.h"

// Global instance of logger
Logger logger;

HRESULT STDMETHODCALLTYPE CProfiler::Initialize(IUnknown *pICorProfilerInfoUnk) 
{ 
	try
	{
		this->AcquireProfilerInterfaces(pICorProfilerInfoUnk);
		this->EnableProfilerEvents();
	}
	catch(HRESULT error)
	{
		wprintf(L"caught HRESULT\n");
		return error;
	}

	return S_OK;
}

//
// Using the passed in interface pointer to IUnknown, query for an interface pointer to ICorProfilerInfo3
//
void CProfiler::AcquireProfilerInterfaces(IUnknown *pUnknown)
{
	HRESULT hr;
	ICorProfilerInfo3* pICorProfiler3;

	hr = pUnknown->QueryInterface(IID_ICorProfilerInfo3, (void **)&pICorProfiler3);
	if(FAILED(hr))
		throw hr;

	m_pICorProfiler3 = pICorProfiler3;
}

//
// Create a DWORD bit mask representing all the events the profiler should tell us about
// and pass it to the profiler.
//
void CProfiler::EnableProfilerEvents()
{
	HRESULT hr;

	DWORD mask = 0;
	mask |= COR_PRF_MONITOR_JIT_COMPILATION;
	mask |= COR_PRF_MONITOR_ENTERLEAVE;

	hr = m_pICorProfiler3->SetEventMask(mask);
	if (FAILED(hr))    
		throw hr;

	hr = m_pICorProfiler3->SetEnterLeaveFunctionHooks3(EnterNaked3, LeaveNaked3, TailcallNaked3);
}

//
// This callback is called as managed types are encountered.
//
HRESULT STDMETHODCALLTYPE CProfiler::JITCompilationStarted(FunctionID functionId, BOOL fIsSafeToBlock)
{ 
	HRESULT hr;

	ClassID classId;
	ModuleID moduleId;
	mdToken token;
	hr = m_pICorProfiler3->GetFunctionInfo2(functionId, NULL, &classId, &moduleId, &token, 0, NULL, NULL);
	if (FAILED(hr))
		return hr;

	CComPtr<IMetaDataImport2> metaDataImport2;
	hr = m_pICorProfiler3->GetModuleMetaData(moduleId, ofRead, IID_IMetaDataImport2, (IUnknown**)&metaDataImport2);
	if (FAILED(hr))
		return hr;

	ULONG nameSize = 512;
	WCHAR methodName[512] = {};
	hr = metaDataImport2->GetMethodProps(token, NULL, methodName, nameSize, &nameSize, NULL, NULL, NULL, NULL, NULL);

	mdTypeDef classToken;
	hr = m_pICorProfiler3->GetClassIDInfo(classId, &moduleId, &classToken );
	if (FAILED(hr))
		return hr;

	DWORD dwTypeDefFlags = 0; // use this to support nested classes
	ULONG classNameSize = 512;
	WCHAR className[512] = {};
	hr = metaDataImport2->GetTypeDefProps(classToken, className, 512, &classNameSize, &dwTypeDefFlags, NULL);
	if (FAILED(hr))
		return hr;

	logger.JITCompilationStarted(functionId, className, methodName);

	return S_OK;
}

